package com.zj.service;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zj.dao.MyUserMapper;
import com.zj.model.MyUser;
import com.zj.restApi.FileUploadApi;
import com.zj.restApi.IdGenratorApi;
import com.zj.util.JwtTokenUtil;
import com.zj.web.bean.MyUserDTO;
import com.zj.web.bean.ResponseResult;
import com.zj.web.controller.AuthRequest;
import com.zj.web.controller.AuthResponse;
import lombok.extern.java.Log;
import org.apache.commons.lang3.RandomStringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

@Service
@Log
public class UserServiceImpl extends ServiceImpl<MyUserMapper, MyUser> implements UserService {
    private final IdGenratorApi idGenratorApi;
    private final FileUploadApi fileUploadApi;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenUtil jwtTokenUtil;
    @Autowired
    private RedisTemplate<String, String> redisTemplate;
    public UserServiceImpl(IdGenratorApi idGenratorApi, FileUploadApi fileUploadApi, PasswordEncoder passwordEncoder, JwtTokenUtil jwtTokenUtil) {
        this.idGenratorApi = idGenratorApi;
        this.fileUploadApi = fileUploadApi;
        this.passwordEncoder = passwordEncoder;
        this.jwtTokenUtil = jwtTokenUtil;
    }

    /**
     * 检查用户名是否存在
     * @param username
     * @return
     */
    public boolean checkUsername(String username) {
        MyUser myUser = this.baseMapper.selectOne(new LambdaQueryWrapper<MyUser>().eq(MyUser::getUserName, username));
        return myUser!=null;
    }

    /**
     * 注册用户
     * @param myUserDTO
     * @return
     */
    @Override
    @Transactional
    public MyUserDTO register(MyUserDTO myUserDTO) {
        //1.检查用户名是否存在
        if(this.checkUsername(myUserDTO.getUserName())){
            throw new RuntimeException("用户名已存在"+myUserDTO.getUserName());
        }
        //1.调用 idGenerator 服务 取出id号
        ResponseEntity<ResponseResult<Long>> responseEntity = idGenratorApi.getNextId();  //jdk动态代理对象
        if(responseEntity.getStatusCode()!= HttpStatus.OK || responseEntity.getBody()==null){
            throw new RuntimeException("调用idGenerator服务失败");
        }
        ResponseResult<Long> responseResult = responseEntity.getBody();
        log.info(responseResult.toString());
        if (responseResult == null || responseResult.getCode() != 1) {
            throw new RuntimeException("调用idGenerator服务失败");
        }
        Long id = responseResult.getData();
        myUserDTO.setUserId(id);
        //2.头像上传
        if(myUserDTO.getAvatarFile()!=null) {
//        文件上传  利用Feign客户端
            ResponseEntity<ResponseResult> responseEntity1 = this.fileUploadApi.uploadFile(new MultipartFile[]{myUserDTO.getAvatarFile()});
            if (responseEntity1.getStatusCode() != HttpStatus.OK || responseEntity1.getBody() == null) {
                throw new RuntimeException("调用fileUpload服务失败");
            }
            ResponseResult responseResult1 = responseEntity1.getBody();
            log.info(responseResult1.toString());
            if (responseResult1 == null || responseResult1.getCode() != 1) {
                throw new RuntimeException("调用fileUpload服务失败");
            }
            List<String> urls = (List<String>) responseResult1.getData();
            myUserDTO.setHeadUrl(urls.get(0));
        }else {
            myUserDTO.setHeadUrl("");
        }
        //3.对密码进行md5加密
//        String password = myUserDTO.getUserPassword();
//        String md5Password = DigestUtils.md5DigestAsHex(password.getBytes());
//        myUserDTO.setUserPassword(md5Password);
        myUserDTO.setUserPassword(passwordEncoder.encode(myUserDTO.getUserPassword()));

        myUserDTO.setUserStatus(USER_STATUS_NORMAL);

        // 3. 将 MyUserDTO 转换为 MyUser 实体对象
        MyUser myUser = new MyUser();

        BeanUtils.copyProperties(myUserDTO, myUser);
        //默认注册为普通用户角色存储为逗号分隔的字符串
        if(myUserDTO.getRoles()==null || myUserDTO.getRoles().isEmpty()){
            myUser.setRoles("CUST");
        }else {
            Set<String> roleSet = myUserDTO.getRoles().stream()
                    .map(String::trim)
                    .collect(Collectors.toSet());
            myUser.setRoles(String.join(",", roleSet));
        }
        // 4. 执行数据库插入操作，传入的是 Banner 实体对象
        Boolean flag = this.save(myUser);
        if(!flag){
            throw new RuntimeException("添加失败");
        }
        return convertToMyUserDTO(myUser);
    }

    /**
     * 登录
     * @param authRequest
     * @return
     */
    @Override
    public AuthResponse login(AuthRequest authRequest) {
        QueryWrapper<MyUser> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("userName",authRequest.getUsername());

        MyUser myUser = this.baseMapper.selectOne(queryWrapper);
        if(myUser==null){
            throw new RuntimeException("用户不存在");
        }
        //1.检查用户状态
        if(myUser.getUserStatus()!=USER_STATUS_NORMAL){
            throw new RuntimeException("用户状态异常");
        }
        //2.检查密码是否正确
        if(!passwordEncoder.matches(authRequest.getPassword(),myUser.getUserPassword())){
            throw new RuntimeException("密码错误");
        }
        //3.登录成功 生成JWT token
        //将逗号分隔的角色字符串转换称Set<String>
        Set<String> roles = Arrays.stream(myUser.getRoles().split(","))
                .map(String::trim)
                .collect(Collectors.toSet());

        String token = jwtTokenUtil.generateToken(myUser.getUserId(), myUser.getUserName(), roles);
        //4.返回token和用户信息
        AuthResponse authResponse = new AuthResponse();
        authResponse.setToken(token);
        authResponse.setMyUserDTO(convertToMyUserDTO(myUser));
        System.out.println(authResponse);
        return authResponse;
    }

    /**
     * 查询所有用户信息
     */
    @Override
    public List<MyUserDTO> getAllUser(Integer userStatus) {
        QueryWrapper<MyUser> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("userStatus",userStatus);
        List<MyUser> myUsers = this.baseMapper.selectList(queryWrapper);
        return myUsers.stream()
                .map(this::convertToMyUserDTO)
                .collect(Collectors.toList());
    }

    /**
     * 根据用户id查询用户信息
     */
    @Override
    public Optional<MyUserDTO> getUserById(Long userId) {
        MyUser myUser = this.baseMapper.selectById(userId);
        if(myUser==null){
            return Optional.empty();
        }
        return Optional.of(convertToMyUserDTO(myUser));
    }

    /**
     * 根据用户id更新用户状态
     */
    @Override
    @Transactional
    public MyUserDTO updateUserStatus(Long userId, Integer userStatus) {
        MyUser myUser = this.baseMapper.selectById(userId);
        if(myUser==null){
            throw new RuntimeException("用户不存在");
        }
        myUser.setUserStatus(userStatus);
        this.baseMapper.updateById(myUser);
        return convertToMyUserDTO(myUser);
    }

    /**
     * 根据用户id更新用户信息
     */
    @Override
    @Transactional
    public MyUserDTO updateUserInfo(Long userId, MyUserDTO myUserDTO) {
        MyUser myUser = this.baseMapper.selectById(userId);
        if(myUser==null){
            throw new RuntimeException("用户不存在");
        }
        //上传头像
        if (myUserDTO.getAvatarFile()!=null){
            //上传头像
            ResponseEntity<ResponseResult> responseEntity1 = this.fileUploadApi.uploadFile(new MultipartFile[]{myUserDTO.getAvatarFile()});
            if(responseEntity1.getStatusCode()!= HttpStatus.OK || responseEntity1.getBody()==null){
                throw new RuntimeException("调用fileUpload服务失败");
            }
            ResponseResult responseResult1 = responseEntity1.getBody();
            log.info(responseResult1.toString());
            if (responseResult1 == null || responseResult1.getCode() != 1) {
                throw new RuntimeException("调用fileUpload服务失败");
            }
            List<String> urls=(List<String>) responseResult1.getData();
            myUserDTO.setHeadUrl( urls.get(0) );
        }
        BeanUtils.copyProperties(myUserDTO,myUser);  //将myUserDTO 中的属性值复制到 myUser 中
        myUser.setUserId(userId);  //设置用户id,因为上一步可能将id转为null了
        this.baseMapper.updateById(myUser);
        return convertToMyUserDTO(myUser);
    }

    @Override
    public MyUserDTO sendVerifyCode(String username, String email) {
        // 1. 生成6位随机验证码
        String code = RandomStringUtils.randomNumeric(6);

        // 2. 存储验证码到Redis（设置5分钟过期）
        redisTemplate.opsForValue().set(
                "verify_code:" + username,
                code,
                5,
                TimeUnit.MINUTES
        );
        MyUserDTO myUserDTO = new MyUserDTO();
        myUserDTO.setUserName(username);
        myUserDTO.setVerifyCode(code);
        myUserDTO.setEmail(email);
        return myUserDTO;
    }

    /**
     * 将 MyUser 实体对象转换为 MyUserDTO 对象
     */
    private MyUserDTO convertToMyUserDTO(MyUser myUser) {
        MyUserDTO myUserDTO = new MyUserDTO();
        myUserDTO.setUserId(myUser.getUserId());
        myUserDTO.setUserName(myUser.getUserName());
        //将逗号分割的角色字符串转换称Set<String>
        if(myUser.getRoles()!=null&& !myUser.getRoles().isEmpty()){
            myUserDTO.setRoles(
                    Arrays.stream(myUser.getRoles().split(","))
                            .map(String::trim)
                            .collect(Collectors.toSet())
            );
        }else {
            myUserDTO.setRoles(Collections.emptySet());
        }
        myUserDTO.setPhone(myUser.getPhone());
        myUserDTO.setEmail(myUser.getEmail());
        myUserDTO.setHeadUrl(myUser.getHeadUrl());
//        System.out.println("图片地址: "+myUser.getHeadUrl());
        myUserDTO.setGender(myUser.getGender());
        myUserDTO.setUserStatus(myUser.getUserStatus());
        //不返回密码
//        System.out.println("图片地址: "+myUserDTO);
        return myUserDTO;
    }
}
